#region license
/*
 * Copyright (C) 2007 CchenSoft.com
 * 
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License 2.1 or later, as
 * published by the Free Software Foundation. See the included License.txt
 * or http://www.gnu.org/copyleft/lesser.html for details.
 * 
 * Author: Billy Zhang
 */
#endregion

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using CchenSoft.Workflow.Config;
using CchenSoft.Workflow.Loader;
using CchenSoft.Workflow.Basic;
using CchenSoft.Workflow.Spi;
using CchenSoft.Workflow.Query;
using System.Reflection;
using Castle.DynamicProxy;

namespace CchenSoft.Workflow
{
    public class WorkflowManager
    {
        private IWorkflowContext context;
        private IConfiguration config;

        public WorkflowManager(IWorkflowContext context)
        {
            this.context = context;
            this.config = DefaultConfiguration.INSTANCE;
        }

        public WorkflowManager(IWorkflowContext context, IConfiguration config)
        {
            this.context = context;
            this.config = config;
        }

        public IWorkflow GetWorkflow(long workflowId)
        {
            IWorkflowEntry entry = config.WorkflowStore.FindEntry(workflowId);
            if (entry != null)
            {
                WorkflowDescriptor descriptor = config.GetWorkflow(entry.WorkflowName);
                if (descriptor != null)
                {
                    IWorkflow wf = CreateWorkflow(context, descriptor, config);
                    wf.WorkflowId = workflowId;
                    return wf;
                }
            }
            return null;
        }

        public IWorkflow CreateWorkflow(string workflowname, int initialActionId, IDictionary inputs)
        {
            WorkflowDescriptor descriptor = config.GetWorkflow(workflowname);
            if (descriptor != null)
            {
                IWorkflow wf = CreateWorkflow(context, descriptor, config);
                wf.Initialize(initialActionId, inputs);
                return wf;
            }
            return null;
        }

        /**
        * Remove the specified workflow descriptor.
        * @param workflowName The workflow name of the workflow to remove.
        * @return true if the workflow was removed, false otherwise.
        * @throws FactoryException If the underlying workflow factory has an error removing the workflow,
        * or if it does not support the removal of workflows.
        */
        public bool RemoveWorkflowDescriptor(string workflowName)
        {
            return config.RemoveWorkflow(workflowName);
        }

        /**
 * Add a new workflow descriptor
 * @param workflowName The workflow name of the workflow to add
 * @param descriptor The workflow descriptor to add
 * @param replace true, if an existing descriptor should be overwritten
 * @return true if the workflow was added, fales otherwise
 * @throws FactoryException If the underlying workflow factory has an error adding the workflow,
 * or if it does not support adding workflows.
 */
        public bool SaveWorkflowDescriptor(string workflowName, WorkflowDescriptor descriptor, bool replace)
        {
            bool success = config.SaveWorkflow(workflowName, descriptor, replace);

            return success;
        }
        
        public IList<long> Query(WorkflowQuery query)
        {
            return config.WorkflowStore.Query(query);
        }

        public IList<long> Query(WorkflowExpressionQuery query)
        {
            return config.WorkflowStore.Query(query);
        }

        /**
         * Get a list of workflow names available
         * @return string[] an array of workflow names.
         */
        public string[] GetWorkflowNames()
        {
            return config.GetWorkflowNames();
        }


        private IWorkflow CreateWorkflow(IWorkflowContext context,
            WorkflowDescriptor descriptor, IConfiguration config)
        {
            ConstructorInfo ci = descriptor.WorkflowType.GetConstructor(
                new Type[] { typeof(IWorkflowContext), typeof(WorkflowDescriptor), typeof(IConfiguration) });
            IWorkflow wf = (IWorkflow)ci.Invoke(new object[] { context, descriptor, config });

            ProxyGenerator gen = new ProxyGenerator();
            return gen.CreateInterfaceProxyWithTarget<IWorkflow>(wf, new WorkflowInterceptor(config));
        }
    }
}
